#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include <stdio.h>
#include <string.h>

void sayHello() {
    printf("hello word\n");
}


#define TYPE_MASK_ENTRY             (mask_entry_get_type ())
#define MASK_ENTRY(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_MASK_ENTRY, MaskEntry))
#define MASK_ENTRY_CLASS(vtable)    (G_TYPE_CHECK_CLASS_CAST ((vtable), TYPE_MASK_ENTRY, MaskEntryClass))
#define IS_MASK_ENTRY(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_MASK_ENTRY))
#define IS_MASK_ENTRY_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), TYPE_MASK_ENTRY))
#define MASK_ENTRY_GET_CLASS(inst)  (G_TYPE_INSTANCE_GET_CLASS ((inst), TYPE_MASK_ENTRY, MaskEntryClass))

typedef struct _MaskEntry MaskEntry;
struct _MaskEntry
{
    GtkEntry entry;
    const char *mask;
};

typedef struct _MaskEntryClass MaskEntryClass;
struct _MaskEntryClass
{
    GtkEntryClass parent_class;
};



static void mask_entry_editable_init (GtkEditableInterface *iface);

static GType mask_entry_get_type (void);
G_DEFINE_TYPE_WITH_CODE (MaskEntry, mask_entry, GTK_TYPE_ENTRY,
                        G_IMPLEMENT_INTERFACE (GTK_TYPE_EDITABLE,
                        mask_entry_editable_init));


static void
mask_entry_set_background (MaskEntry *entry)
{
    if (entry->mask)
    {
        if (!g_regex_match_simple (entry->mask, gtk_editable_get_text (GTK_EDITABLE (entry)), 0, 0))
        {
            PangoAttrList *attrs;

            attrs = pango_attr_list_new ();
            pango_attr_list_insert (attrs, pango_attr_foreground_new (65535, 32767, 32767));
            gtk_entry_set_attributes (GTK_ENTRY (entry), attrs);
            pango_attr_list_unref (attrs);
            return;
        }
    }

    gtk_entry_set_attributes (GTK_ENTRY (entry), NULL);
}


static void
mask_entry_changed (GtkEditable *editable)
{
    mask_entry_set_background (MASK_ENTRY (editable));
}


static void
mask_entry_init (MaskEntry *entry)
{
    entry->mask = NULL;
}


static void
mask_entry_class_init (MaskEntryClass *klass)
{ }


static void
mask_entry_editable_init (GtkEditableInterface *iface)
{
    iface->changed = mask_entry_changed;
}

/************************************************************/

static void is_capital_sensitive(GtkCellLayout *cell_layou, 
                                    GtkCellRenderer *cell, 
                                    GtkTreeModel *tree_mode, 
                                    GtkTreeIter *iter, 
                                    gpointer data) {
    gboolean sensitive;

    sensitive = !gtk_tree_model_iter_has_child(tree_mode, iter);

    g_object_set(cell, "sensitive", sensitive, NULL);
}

static GtkTreeModel * create_capital_store() {
    struct {
        const char *group;
        const char *capital;
    } capitals[] = {
        { "A - B", NULL },
        { NULL, "Alibaba" },
        { NULL, "AcFun" },
        { NULL, "BiliBili" },
        { "C - D", NULL },
        { NULL, "CNTV" },
        { NULL, "CCTV" },
        { NULL, "Daway" },
        { NULL, NULL }
    };

    GtkTreeIter iter, iter2;
    GtkTreeStore *store;
    int i;

    store = gtk_tree_store_new(1, G_TYPE_STRING);

    for (i=0; capitals[i].group || capitals[i].capital; i++) {
        if (capitals[i].group) {
            gtk_tree_store_append(store, &iter, NULL);
            gtk_tree_store_set(store, &iter, 0, capitals[i].group, -1);
        } else if (capitals[i].capital) {
            gtk_tree_store_append(store, &iter2, &iter);
            gtk_tree_store_set(store, &iter2, 0, capitals[i].capital, -1);
        }
    }
    return GTK_TREE_MODEL(store);
}


enum
{
    ICON_NAME_COL,
    TEXT_COL
};

static GtkTreeModel* create_icon_store(void) {
    const char *icon_names[6] = {
        "dialog-warning",
        "process-stop",
        "document-new",
        "edit-clear",
        NULL,
        "document-open"
    };
    const char *labels[6] = {
        N_("Warning"),
        N_("Stop"),
        N_("New"),
        N_("Clear"),
        NULL,
        N_("Open")
    };

    GtkTreeIter iter;
    GtkListStore *store;
    int i;

    store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);

    for (i = 0; i < G_N_ELEMENTS (icon_names); i++)
        {
        if (icon_names[i])
            {
            gtk_list_store_append (store, &iter);
            gtk_list_store_set (store, &iter,
                                ICON_NAME_COL, icon_names[i],
                                TEXT_COL, _(labels[i]),
                                -1);
            }
        else
            {
            gtk_list_store_append (store, &iter);
            gtk_list_store_set (store, &iter,
                                ICON_NAME_COL, NULL,
                                TEXT_COL, "separator",
                                -1);
            }
        }

    return GTK_TREE_MODEL (store);
}

static void set_sensitive(GtkCellLayout *cell_layout, GtkCellRenderer *cell,
                            GtkTreeModel *tree_model, GtkTreeIter *iter,
                            gpointer data) {
    GtkTreePath *path;
    int *indices;
    gboolean sensitive;

    path = gtk_tree_model_get_path(tree_model, iter);
    indices = gtk_tree_path_get_indices(path);
    sensitive = indices[0] != 1;
    gtk_tree_path_free(path);

    g_object_set(cell, "sensitive", sensitive, NULL);
}

static gboolean is_separator(GtkTreeModel *model, GtkTreeIter *iter, gpointer data) {
    GtkTreePath *path;
    gboolean result;

    path = gtk_tree_model_get_path(model, iter);
    result = gtk_tree_path_get_indices(path)[0] == 4;
    gtk_tree_path_free(path);

    return result;
}

/************************************************************/

static void paste_received(GObject *source_object, GAsyncResult *result, gpointer user_data) {
    GdkClipboard *clipboard;
    GtkWidget *entry;
    char *text;
    GError *error = NULL;

    clipboard = GDK_CLIPBOARD(source_object);
    entry = GTK_WIDGET(user_data);

    text = gdk_clipboard_read_text_finish(clipboard, result, &error);

    if (text) {
        gtk_editable_set_text(GTK_EDITABLE(entry), text);
        g_free(text);
    } else {

    }
}

static void paste_entry(GtkWidget *button, gpointer *user_data) {
    GtkWidget *entry;
    GdkClipboard *clipboard;
    const char *text;

    entry = GTK_WIDGET(user_data);
    clipboard = gtk_widget_get_clipboard(entry);
    
    gdk_clipboard_read_text_async(clipboard, NULL, paste_received, entry);
}

static void copy_entry(GtkWidget *button, gpointer *user_data) {
    GtkWidget *entry;
    GdkClipboard *clipboard;
    const char *text;

    entry = GTK_WIDGET(user_data);
    clipboard = gtk_widget_get_clipboard(entry);
    text = gtk_editable_get_text(GTK_EDITABLE(entry));
    char buf[strlen(text)];
    buf[strlen(text)] = '\0';

    for (int i=0; i<strlen(text); i++) {
        printf("%d ", text[i]);
        buf[i] = text[i];
        fflush(stdout);
    }
    printf("\n%s --\n%s --\n", text, buf);
    // gdk_clipboard_read_text_async(clipboard, NULL, paste_received, entry);
    gdk_clipboard_set_text(clipboard, buf);
}

/************************************************************/

static void activate(GtkApplication *app, gpointer user_data) {
    GtkWidget *window;
    GtkWidget *button;
    GtkWidget *vbox, *hbox, *box;
    GtkWidget *label;
    GtkWidget *entry;
    GtkWidget *frame;
    GtkWidget *combo;
    GtkTreeModel *model;
    GtkCellRenderer *renderer;
    GtkTreePath *path;
    GtkTreeIter iter;


    window = gtk_application_window_new(app);
    gtk_window_set_title(GTK_WINDOW(window), "editor-tr");
    gtk_window_set_default_size(GTK_WINDOW(window), 200, 100);

    vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
    gtk_widget_set_margin_start(vbox, 8);
    gtk_widget_set_margin_end(vbox, 8);
    gtk_widget_set_margin_top(vbox, 8);
    gtk_widget_set_margin_bottom(vbox, 8);
    gtk_window_set_child(GTK_WINDOW(window), vbox);

    label = gtk_label_new("MQTT Example");
    gtk_box_append(GTK_BOX(vbox), label);

    button = gtk_button_new_with_label("Hello World");
    g_signal_connect(button, "clicked", G_CALLBACK(sayHello), window);
    g_signal_connect_swapped(button, "clicked", G_CALLBACK(gtk_window_destroy), window);
    // gtk_box_append(GTK_BOX(vbox), button);

    box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);

    frame = gtk_frame_new("Clipboard Example:");
    gtk_box_append(GTK_BOX(vbox), frame);
    gtk_frame_set_child(GTK_FRAME(frame), box);

    hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4);
    gtk_widget_set_margin_start(hbox, 8);
    gtk_widget_set_margin_end(hbox, 8);
    gtk_widget_set_margin_top(hbox, 8);
    gtk_widget_set_margin_bottom(hbox, 8);
    gtk_box_append(GTK_BOX(box), hbox);

    entry = gtk_entry_new();
    gtk_box_append(GTK_BOX(hbox), entry);

    button = gtk_button_new_with_label("Copy");
    gtk_box_append(GTK_BOX(hbox), button);
    g_signal_connect(button, "clicked", G_CALLBACK(copy_entry), entry);

////////////////////////////////////////////////////////////////////////////////

    hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4);
    gtk_widget_set_margin_start(hbox, 8);
    gtk_widget_set_margin_end(hbox, 8);
    gtk_widget_set_margin_top(hbox, 8);
    gtk_widget_set_margin_bottom(hbox, 8);
    gtk_box_append(GTK_BOX(box), hbox);

    entry = gtk_entry_new();
    gtk_box_append(GTK_BOX(hbox), entry);

    button = gtk_button_new_with_label("Paste");
    gtk_box_append(GTK_BOX(hbox), button);
    g_signal_connect(button, "clicked", G_CALLBACK(paste_entry), entry);

    model = create_icon_store();
    combo = gtk_combo_box_new_with_model(model);
    g_object_unref(model);
    gtk_box_append(GTK_BOX(vbox), combo);

    renderer = gtk_cell_renderer_pixbuf_new();
    gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo), renderer, FALSE);
    gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo), renderer, "icon-name", ICON_NAME_COL, NULL);
    gtk_cell_layout_set_cell_data_func(GTK_CELL_LAYOUT(combo), renderer, set_sensitive, NULL, NULL);
    
    renderer = gtk_cell_renderer_text_new();
    gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo), renderer, FALSE);
    gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo), renderer, "text", TEXT_COL, NULL);
    gtk_cell_layout_set_cell_data_func(GTK_CELL_LAYOUT(combo), renderer, set_sensitive, NULL, NULL);
    
    gtk_combo_box_set_row_separator_func(GTK_COMBO_BOX(combo), is_separator, NULL, NULL);
    gtk_combo_box_set_active(GTK_COMBO_BOX(combo), 0);


    frame = gtk_frame_new("Where are we");
    gtk_box_append(GTK_BOX(vbox), frame);

    box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
    gtk_widget_set_margin_start(box, 5);
    gtk_widget_set_margin_end(box, 5);
    gtk_widget_set_margin_top(box, 5);
    gtk_widget_set_margin_bottom(box, 5);
    gtk_frame_set_child(GTK_FRAME(frame), box);

    model = create_capital_store();
    combo = gtk_combo_box_new_with_model(model);
    g_object_unref(model);
    gtk_box_append(GTK_BOX(box), combo);

    renderer = gtk_cell_renderer_text_new();
    gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo), renderer, TRUE);
    gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo), renderer, "text", 0, NULL);
    gtk_cell_layout_set_cell_data_func(GTK_CELL_LAYOUT(combo), renderer, is_capital_sensitive, NULL, NULL);


    path = gtk_tree_path_new_from_indices(0, 8, -1);
    gtk_tree_model_get_iter(model, &iter, path);
    gtk_tree_path_free(path);
    gtk_combo_box_set_active_iter(GTK_COMBO_BOX(combo), &iter);

    frame = gtk_frame_new("Editable");
    gtk_box_append(GTK_BOX(vbox), frame);

    box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
    gtk_widget_set_margin_start(box, 5);
    gtk_widget_set_margin_end(box, 5);
    gtk_widget_set_margin_top(box, 5);
    gtk_widget_set_margin_bottom(box, 5);
    gtk_frame_set_child(GTK_FRAME(frame), box);

    combo = gtk_combo_box_new_with_entry();
    gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), "One");
    gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), "Two");
    gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), "2\302\275");
    gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), "Three");
    gtk_box_append(GTK_BOX(box), combo);

    entry = g_object_new(TYPE_MASK_ENTRY, NULL);
    MASK_ENTRY (entry)->mask = "^([0-9]*|One|Two|2\302\275|Three)$";
    // entry = gtk_entry_new();
    gtk_combo_box_set_child(GTK_COMBO_BOX(combo), entry);

    gtk_widget_show(window);
}

/************************************************************/

int	main(int argc, char **argv) {

    GtkApplication *app;
    int status;

    app = gtk_application_new("editor.tr", G_APPLICATION_FLAGS_NONE);
    g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
    status = g_application_run(G_APPLICATION(app), argc, argv);
    g_object_unref(app);
    return status;
}
